package core

import (
	"fmt"
	"log"
	"time"

	"github.com/google/gopacket"
	"github.com/google/gopacket/layers"
	"github.com/google/gopacket/pcap"
	"github.com/google/gopacket/tcpassembly"
	"github.com/google/gopacket/tcpassembly/tcpreader"
)

// 实现原理
// 原始网络包 → pcap捕获 → gopacket解析 → tcpassembly重组 → ReaderStream → 插件ResolveStream

type Dispatch struct {
	device  string // 网络设备名，如 "eth0", "en0"
	payload []byte // 未使用的字段，可能预留用于存储数据
	Plug    *Plug  // 插件实例，包含协议解析逻辑
}

func NewDispatch(plug *Plug, cmd *Cmd) *Dispatch {
	return &Dispatch{
		Plug:   plug,       // 传入插件实例
		device: cmd.Device, // 从命令行参数获取设备名
	}
}

// Capture函数是核心协程
// → core.(*Dispatch).Capture
// → core.(*Assembler).AssembleWithTimestamp
// → core.(*StreamPool).getConnection
// → core.(*ProtocolStreamFactory).New
func (d *Dispatch) Capture() {
	// 初始化设备（委托给pcap库）
	handle, err := pcap.OpenLive(d.device, 65535, false, pcap.BlockForever)
	if err != nil {
		log.Fatal(err)
		return
	}

	// 设置过滤器（使用插件提供的BPF规则）
	fmt.Println(d.Plug.BPF)
	err = handle.SetBPFFilter(d.Plug.BPF)
	if err != nil {
		log.Fatal(err)
	}

	// 创建包源（委托给gopacket）
	src := gopacket.NewPacketSource(handle, handle.LinkType())
	packets := src.Packets()

	// 设置流重组工厂
	// 作用: 创建TCP流重组所需的组件
	// streamFactory: 负责为每个新TCP流创建处理器
	// streamPool: 管理流对象的复用
	// assembler: 实际的TCP流重组器
	streamFactory := &ProtocolStreamFactory{
		dispatch: d,
	}
	streamPool := NewStreamPool(streamFactory)
	assembler := NewAssembler(streamPool)
	ticker := time.Tick(time.Minute)

	//loop until ctrl+z
	for {
		select {
		case packet := <-packets:
			// 过滤非TCP包(只是简单的过滤和预处理, 捕获原始包，进行基础过滤，然后交给TCP流重组器)
			if packet.NetworkLayer() == nil ||
				packet.TransportLayer() == nil ||
				packet.TransportLayer().LayerType() != layers.LayerTypeTCP {
				fmt.Println("ERR : Unknown Packet -_-")
				continue
			}

			// 抓到符合tcp包的数据 (仅是tcp数据, 具体的filter去plugin内实现) 提取TCP层数据并交给重组器(进入core.Assembler内, 也就是重组器)
			tcp := packet.TransportLayer().(*layers.TCP)
			assembler.AssembleWithTimestamp(
				packet.NetworkLayer().NetworkFlow(),
				tcp, packet.Metadata().Timestamp,
			)
		case <-ticker:
			// 定期清理过期流（2分钟无活动）
			assembler.FlushOlderThan(time.Now().Add(time.Minute * -2))
		}
	}
}

type ProtocolStreamFactory struct {
	dispatch *Dispatch // 持有Dispatch引用，用于访问插件
}

type ProtocolStream struct {
	net, transport gopacket.Flow          // 流标识信息（源/目标IP和端口）
	r              tcpreader.ReaderStream // 提供io.Reader接口的流
}

// 由核心协程Capture走到这里, 这是很重要的一点, sniffer的框架核心就是这套流程
func (m *ProtocolStreamFactory) New(net, transport gopacket.Flow) tcpassembly.Stream {
	//printStack()

	// 创建新的流对象
	stm := &ProtocolStream{
		net:       net,                         // 网络层流信息（IP地址）
		transport: transport,                   // 传输层流信息（端口）
		r:         tcpreader.NewReaderStream(), // 读取器流
	}

	// 启动一个异步协程处理这个TCP流的数据
	// 实际就是goroutine将数据流传递给插件内, 但是走了异步, 主核心协程还是回到: core.(*Dispatch).Capture
	go m.dispatch.Plug.ResolveStream(net, transport, &(stm.r))

	return &(stm.r) // 返回流接口供重组器使用(tcpassembly)
}
